<?php
/**
 ***********************************************************************************************************************
 * 访问记录处理类
 * @author llq
 ***********************************************************************************************************************
 */
namespace soa\access\model;
/**
 * Class record
 * @package soa\access\model
 */
class record
{
    /**
     * IP
     */
    const LIMIT_IP_PREFIX = 'access:record:ip:';

    /**
     * CLIENT
     */
    const LIMIT_CLIENT_PREFIX = 'access:record:client:';

    /**
     * @var array
     */
    private $by_ip_fields = [
        'daily',
        'hourly',
        'minutely',
        'update_at'
    ];

    /**
     * @var array
     */
    private $by_client_fields = [
        'daily',
        'hourly',
        'minutely',
        'update_at',
        'ip'
    ];

    /**
     * @var bool
     */
    private $set_expire = false;

    /**
     * @param $service
     */
    public function __construct($service)
    {
        if(empty($this->service = $service)) {
            logCritical('Error access service name give !', 'access', 'access');
            die('Error access service name give !');
        }
    }

    /**
     * @param $ip
     * @return array
     */
    public function orzRecordByIP($ip)
    {
        $record_history = $this->getByIP($ip);
        $data = [];
        $data['update_at'] = time();
        // 记录IP级别的访问记录
        $data['daily'] = empty($record_history['daily']) ? 1 : (intval($record_history['daily']) + 1);
        // 清空过期访问记录
        if(empty($record_history['update_at']) || date('d', $record_history['update_at']) != date('d')) {
            $data['daily'] = 1;
        }
        $data['hourly'] = empty($record_history['hourly']) ? 1 : (intval($record_history['hourly']) + 1);
        // 清空过期访问记录
        if(empty($record_history['update_at']) || date('H', $record_history['update_at']) != date('H')) {
            $data['hourly'] = 1;
        }
        $data['minutely'] = empty($record_history['minutely']) ? 1 : (intval($record_history['minutely']) + 1);
        // 清空过期访问记录
        if(empty($record_history['update_at']) || date('i', $record_history['update_at']) != date('i')) {
            $data['minutely'] = 1;
        }
        return $data;
    }

    /**
     * @param $client
     * @return array
     */
    public function orzRecordByClient($client)
    {
        $record_history = $this->getByClient($client);
        //myprint($record_history);
        $data = [];
        $data['update_at'] = time();
        // 记录IP级别的访问记录
        $data['daily'] = empty($record_history['daily']) ? 1 : (intval($record_history['daily']) + 1);
        // 清空过期访问记录
        if(empty($record_history['update_at']) || date('d', $record_history['update_at']) != date('d')) {
            $data['daily'] = 1;
        }
        $data['hourly'] = empty($record_history['hourly']) ? 1 : (intval($record_history['hourly']) + 1);
        // 清空过期访问记录
        if(empty($record_history['update_at']) || date('H', $record_history['update_at']) != date('H')) {
            $data['hourly'] = 1;
        }
        $data['minutely'] = empty($record_history['minutely']) ? 1 : (intval($record_history['minutely']) + 1);
        // 清空过期访问记录
        if(empty($record_history['update_at']) || date('i', $record_history['update_at']) != date('i')) {
            $data['minutely'] = 1;
        }
        return $data;
    }

    /**
     * @param $ip
     * @param array $dict
     * @return bool|int
     */
    public function updateByIP($ip, array $dict)
    {
        if(empty($ip) || !is_string($ip) || empty($dict)) {
            return false;
        }
        foreach($dict as $key => $val) {
            if(!in_array($key, $this->by_ip_fields)) {
                unset($dict[$key]);
            }
        }
        $key = self::LIMIT_IP_PREFIX . $this->service . ':' . $ip;
        $ret = $this->getRedisService()->hMset($key, $dict);
        if($this->set_expire == true) {
            // 次日零点过期 仅仅记录一天数据 减少redis内存占用
            $expireat = strtotime('+1 day', strtotime(date('Y-m-d')));
            $this->getRedisService()->expireat($key, $expireat);
        }
        return $ret;
    }

    /**
     * @param $ip
     * @return array|bool
     */
    public function getByIP($ip)
    {
        if(empty($ip) || !is_string($ip)) {
            return false;
        }
        $ret = $this->getRedisService()->hGetAll(self::LIMIT_IP_PREFIX . $this->service . ':' . $ip);
        if(empty($ret)) {
            $this->set_expire = true;
        }
        return $ret;
    }

    /**
     * @param $client
     * @param array $dict
     * @return bool|int
     */
    public function updateByClient($client_id, array $dict)
    {
        if(empty($client_id) || !is_string($client_id) || empty($dict)) {
            return false;
        }
        foreach($dict as $key => $val) {
            if(!in_array($key, $this->by_client_fields)) {
                unset($dict[$key]);
            }
        }
        $key = self::LIMIT_CLIENT_PREFIX . $this->service . ':' . $client_id;
        $ret = $this->getRedisService()->hMset($key, $dict);
        //myprint($ret);
        if($this->set_expire == true) {
            // 次日零点过期 仅仅记录一天数据 减少redis内存占用
            $expireat = strtotime('+1 day', strtotime(date('Y-m-d')));
            $this->getRedisService()->expireat($key, $expireat);
        }
        return $ret;
    }

    /**
     * @param $client
     * @return array|bool
     */
    public function getByClient($client)
    {
        if(empty($client) || !is_string($client)) {
            return false;
        }
        $ret = $this->getRedisService()->hGetAll(self::LIMIT_CLIENT_PREFIX . $this->service . ':' . $client);
        if(empty($ret)) {
            $this->set_expire = true;
        }
        return $ret;
    }

    /**
     * @var \artisan\cache\cacheDriver
     */
    private $redisService;

    /**
     * @return \artisan\cache\cacheDriver
     */
    private function getRedisService()
    {
        if(empty($this->redisService)) {
            $this->redisService = \artisan\cache::connect('firewall');
        }
        return $this->redisService;
    }
}